﻿using System;
using System.Data.Objects.DataClasses;
using Arquitetura.Architectural.Model;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.Unity;

namespace Arquitetura.Architectural.BusinessLogic.Validation
{
    public abstract class ValidationBase : BusinessLogicBase, IValidationBase
    {
        #region Propriedade(s)
        protected Result Result
        { get; set; }
        #endregion Propriedade(s)

        #region Construtor(es)
        public ValidationBase()
        {
            Result = new Result();
        }

        public ValidationBase(IUnityContainer unityContainer)
            : base(unityContainer)
        {
            Result = new Result();
        }
        #endregion Construtor(es)

        #region Método(s)
        public virtual void Clear()
        {
            Result.Clear();
        }

        protected virtual void ValidateDataBasicRules() { }

        protected virtual void ValidateDataAdvancedRules() { }

        protected virtual void ValidateBusinessRules() { }

        public Result Validate()
        {
            Result.Clear();
            ValidateDataBasicRules();
            ValidateDataAdvancedRules();
            ValidateBusinessRules();
            return new Result(Result);
        }

        protected void AddResults(Result result)
        {
            result.Success &= result.Success;
            result.Messages.AddRange(result.Messages);
        }

        protected void AddResult(bool sucess, ResultMessage message)
        {
            if (message == null)
                throw new ArgumentNullException("A mensagem de erros de validação não pode ser nula");

            Result.Success &= sucess;
            Result.Messages.Add(message);
        }
        #endregion Método(s)
    }

    public abstract class ValidationBase<T, O> : ValidationBase, IValidationBase<T, O>
    {
        #region Propriedade(s)
        protected O Operation
        { get; set; }

        protected T Target
        { get; set; }
        #endregion Propriedade(s)

        #region Construtor(es)
        protected ValidationBase() { }

        /// <summary>
        /// Usado somente pelo método Factory
        /// </summary>
        protected ValidationBase(IUnityContainer unityContainer)
            : base(unityContainer) { }
        #endregion Construtor(es)

        #region Método(s)
        public override void Clear()
        {
            base.Clear();
            Target = default(T);
            Operation = default(O);
        }

        public IValidationBase<T, O> Setup(T target, O operation)
        {
            base.Clear();
            Target = target;
            Operation = operation;
            return this;
        }

        protected override void ValidateDataBasicRules()
        {
            ValidateBaseType(Target, typeof(T).BaseType);
            Validator<T> validator = ValidationFactory.CreateValidator<T>(Operation.ToString());
            ValidationResults validationResults = validator.Validate(Target);
            Result.Success &= validationResults.IsValid;
            Result.ConsolidateValidationResult(validationResults);
        }

        private void ValidateBaseType(T Target, Type baseType)
        {
            if ((baseType != typeof(object)) &&      //Tipos Sem Persistencia (POCOS)
               (baseType != typeof(EntityObject)))   //Tipo Com Persistencia (EntityFramework)
            {
                ValidateBaseType(Target, baseType.BaseType);
                Validator validator = ValidationFactory.CreateValidator(baseType, Operation.ToString());
                ValidationResults validationResults = validator.Validate(Target);
                Result.Success &= validationResults.IsValid;
                Result.ConsolidateValidationResult(validationResults);
            }
        }
        #endregion Método(s)
    }
}
